package com.liuym.common.db;

import com.jsmframe.interceptor.PageInterceptor;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import org.apache.ibatis.io.VFS;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.boot.autoconfigure.SpringBootVFS;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;

import java.util.Properties;

/**
 * @author YeQiang
 * @ClassName: BasicDataSource
 * @Description: TODO
 * @date 2018年4月13日 下午2:36:55
 */

public class BasicDataSource {

    // JDBC 驱动程序提供的 DataSource 类的名称，如果使用了jdbcUrl则不需要此属性
    @Value("${db.datasource.driverClassName}")
    protected String driverClassName;

    // 数据库账户
    @Value("${db.datasource.username}")
    protected String username;

    // 数据库账户密码
    @Value("${db.datasource.password}")
    protected String password;

    // 连接池中创建的连接默认是否自动提交事务；默认为true
    @Value("${db.datasource.defaultAutoCommit}")
    protected boolean defaultAutoCommit;

    // 连接超时时间（毫秒），如果在没有连接可用的情况下等待超过此时间，则抛出 SQLException; 默认 60000 ms
    @Value("${db.datasource.hikari.connectionTimeout}")
    protected int connectionTimeout;

    // 最小空闲连接数，HikariCP 建议不要设置此值，而是充当固定大小的连接池；不过具体可以根据业务场景而定
    @Value("${db.datasource.hikari.minimumIdle}")
    protected int minimumIdle;

    // 连接池中可同时连接的最大连接数，当池中没有空闲连接可用时，就会阻塞直到超出connectionTimeout设定的数值；default  60000 ms
    @Value("${db.datasource.hikari.maximum-pool-size}")
    protected int maximumPoolSize;

    // 连接池每分配一条连接前执行的查询语句（如：SELECT 1），以验证该连接是否是有效的。如果你的驱动程序支持 JDBC4，HikariCP 强烈建议我们不要设置此属性
    @Value("${db.datasource.hikari.connection-test-query}")
    protected String connectionTestQuery;

    // mybatis 配置文件所在目录
    @Value("${db.mybatis.xml.path:classpath:/mybatis/*.xml}")
    protected String mybatisXmlPath;

    // 默认的加载的mybatis alias别名类 所在目录
    @Value("${db.mybatis.entity.path:null}")
    protected String mybatisEntityPath;

    // hikari 缓存配置,以下为默认配置参数这个参数在使用ECTemple分库时不能设置为true,否则use db的语句会不生效
    @Value("${db.datasource.hikari.cachePrepStmts:false}")
    protected boolean cachePrepStmts;

    // 连接池大小默认25，官方推荐250-500
    @Value("${db.datasource.hikari.prepStmtCacheSize:250}")
    protected int prepStmtCacheSize;

    //单条语句最大长度默认256，官方推荐2048
    @Value("${db.datasource.hikari.prepStmtCacheSqlLimit:2048}")
    protected int prepStmtCacheSqlLimit;

    //新版本MySQL支持服务器端准备，开启能够得到显著性能提升
    @Value("${db.datasource.hikari.useServerPrepStmts:true}")
    protected boolean useServerPrepStmts;

    // datasource 配置类
    protected HikariDataSource dataSource(String url) {
        HikariConfig config = new HikariConfig();
        config.setMaximumPoolSize(maximumPoolSize);
        config.setDriverClassName(driverClassName);
        config.setUsername(username);
        config.setPassword(password);
        config.setConnectionTimeout(connectionTimeout);
        config.setMinimumIdle(minimumIdle);
        config.setAutoCommit(defaultAutoCommit);
        config.setConnectionTimeout(connectionTimeout);
        config.setConnectionTestQuery(connectionTestQuery);
        //缓存设置
        config.addDataSourceProperty("cachePrepStmts", cachePrepStmts);
        config.addDataSourceProperty("prepStmtCacheSize", prepStmtCacheSize);
        config.addDataSourceProperty("prepStmtCacheSqlLimit", prepStmtCacheSqlLimit);
        config.addDataSourceProperty("useServerPrepStmts", useServerPrepStmts);
        config.setJdbcUrl(url);
        HikariDataSource ds = new HikariDataSource(config);
        return ds;
    }

    // 获取sqlsessionfactory公共方法 
    protected SqlSessionFactory getSqlSessionFactory(HikariDataSource dataSource) throws Exception {
        //在springboot的环境下，Mybatis的DefaultVFS这个扫包会出现问题，所以只能修改VFS
        VFS.addImplClass(SpringBootVFS.class);
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        // 设置数据源
        sqlSessionFactoryBean.setDataSource(dataSource);
        // 设置查找器
        PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
        // 自动扫描mybatis配置文件目录文件
        sqlSessionFactoryBean.setMapperLocations(resolver.getResources(mybatisXmlPath));
        // 扫描xml中别名类所在的目录---建议所有mybatis使用的entity 放在同一个目录下
        sqlSessionFactoryBean.setTypeAliasesPackage(mybatisEntityPath);
        Configuration configuration = new Configuration();
        configuration.setLogImpl(org.apache.ibatis.logging.log4j2.Log4j2Impl.class);
        sqlSessionFactoryBean.setConfiguration(configuration);
        PageInterceptor pageInterceptor = new PageInterceptor();
        Properties properties = new Properties();
        properties.setProperty("helperDialect", "mysql");
        properties.setProperty("reasonable", "true");
        properties.setProperty("supportMethodsArguments", "true");
        properties.setProperty("params", "count=countSql");
        properties.setProperty("autoRuntimeDialect", "true");
        pageInterceptor.setProperties(properties);
        Interceptor[] plugins = {pageInterceptor};
        sqlSessionFactoryBean.setPlugins(plugins);
        return sqlSessionFactoryBean.getObject();
    }

    // 获取sqlsessionfactory公共方法
    protected HikariDataSource getDataSource(String url) {
        HikariDataSource ds = this.dataSource(url);
        return ds;
    }
}
